/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.google.code.netbuilder.dal.services;

import com.google.code.netbuilder.dal.entities.Cable;
import com.google.code.netbuilder.dal.entities.Equipment;
import com.google.code.netbuilder.dal.entities.ManagedObject;
import com.google.code.netbuilder.dal.entities.Port;
import com.google.code.netbuilder.dal.entities.Wire;
import com.google.code.netbuilder.dal.providers.IPortProvider;
import com.google.code.netbuilder.dal.providers.IWireProvider;
import com.google.code.netbuilder.logging.NetBuilderLogger;
import com.google.code.netbuilder.logging.NetBuilderLoggerFactory;
import java.util.LinkedList;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.faces.bean.ManagedBean;

/**
 *
 * @author Alexander Schrebakov
 */
@ManagedBean
@Stateless
public class ConnectionService {
    
    private static final NetBuilderLogger LOGGER = NetBuilderLoggerFactory.getNetBuilderLogger(ConnectionService.class);
    
    @EJB
	private IWireProvider wp;
    
    @EJB
	private IPortProvider pp;
    
    public void createConnection(Port port1, Port port2, Cable cable) {
        if (port1.getEquipment().equals(port2.getEquipment()))
            throw new IllegalArgumentException("This ports belongs to same equipment.");
        if (!port1.getEquipment().getType().equals(port2.getEquipment().getType()) )
            throw new IllegalArgumentException("Equipments have different types.");
        if (!port1.getEquipment().getType().equals(cable.getType()) )
            throw new IllegalArgumentException("Equipments and cable have different types.");
        Wire wire_to = this.findFreeWire(cable);
        if (wire_to == null) 
            throw new IllegalArgumentException("Cable does not have enough free wires.");
        wire_to.setFromPort(port1);
        wire_to.setToPort(port2);
        wp.update(wire_to);
        Wire wire_from = this.findFreeWire(cable);
        if (wire_from == null) {
            wire_to.setFromPort(null);
            wire_to.setToPort(null);
            wp.update(wire_to);            
            throw new IllegalArgumentException("Cable does not have enough free wires.");
        }
        wire_from.setFromPort(port2);
        wire_from.setToPort(port1);
        wp.update(wire_from);
        pp.refresh();
    }
    
    private Wire findFreeWire(Cable cable) {
        for (Wire wire : cable.getCableWires()) {
            if (wire.getFromPort() == null && wire.getToPort() == null)
                   return wire;
        }
        return null;
    }
    
    public LinkedList<ManagedObject> findPath(Equipment start_eq, Equipment finish_eq) {
        
        LinkedList<ManagedObject> list = new LinkedList<ManagedObject>();
        Port outerPort = null;
        Port innerPort = null;
        Equipment currentEquipment = null;
        
        if (start_eq.equals(finish_eq))
            throw new IllegalArgumentException("Selected the same equipment.");
        
        for (Port port : start_eq.getPorts()) {
            if (!list.isEmpty())
                list.clear();
            list.add(start_eq);
            list.add(port);
            outerPort = port.getOuterConnectedPort();
            while (outerPort != null) {
                Cable cable = outerPort.getWire().getCable();
                list.add(cable);
                list.add(outerPort);
                currentEquipment = outerPort.getEquipment();
                list.add(currentEquipment);
                if (currentEquipment.equals(finish_eq))
                    return list;
                if (currentEquipment.equals(start_eq))
                    break;
                innerPort = outerPort.getInnerConnectedPort();
                list.add(innerPort);
                if (innerPort == null) 
                    break;
                outerPort = innerPort.getOuterConnectedPort();
            }
        }
        return new LinkedList();
    }
    
}